23. 合并 K 个升序链表

23. 合并 K 个升序链表

Similar Question

Solution Tips

方案一: 暴力法

取得值,排序后,重建链表

function ListNode(val){
  this.val = val
  this.next = null
}
var mergeKLists = function(lists) {
  const arr = []
  list.forEach((list) => {
    while(list!==null){
      arr.push(list.val)
      list = list.next
    }
  })
  arr.sort((a,b)=>a-b)
  const val = arr.shift()
  // 边界情况
  if(val===undefined) return null
  const head = new ListNode(val)
  let cur = head
  // 重建链表
  for (let i = 0; i < arr.length; i++) {
    cur.next = new ListNode(arr[i])
    cur = cur.next
  }
  return head
}

复杂度分析

时间复杂度:O(NlogN) ,其中 N 是节点的总数目。

空间复杂度:O(N)。

方案二: 逐一比较

比较 k 个节点(每个链表的首节点),获得最小值的节点。将选中的节点接在最终有序链表的后面。

复杂度分析

时间复杂度: O(kN) ,其中 k 是链表的数目。

空间复杂度:

方案三: 用优先队列优化方法 2

几乎与上述方法一样,除了将 比较环节优先队列 进行了优化。你可以参考 这里 获取更多信息。

from Queue import PriorityQueue

class Solution(object):
    def mergeKLists(self, lists):
        """
        :type lists: List[ListNode]
        :rtype: ListNode
        """
        head = point = ListNode(0)
        q = PriorityQueue()
        for l in lists:
            if l:
                q.put((l.val, l))
        while not q.empty():
            val, node = q.get()
            point.next = ListNode(val)
            point = point.next
            node = node.next
            if node:
                q.put((node.val, node))
        return head.next

方案四: 逐一两两合并链表

将合并 k 个链表的问题转化成合并 2 个链表 k-1 次。这里是 合并两个有序链表 的题目。

复杂度分析

时间复杂度: O(kN) ,其中 k 是链表的数目。

空间复杂度:O(1)

方案五: 分治

这个方法沿用了上面的解法,但是进行了较大的优化。我们不需要对大部分节点重复遍历多次。

因此,我们在每一次配对合并的过程中都会遍历几乎全部 N 个节点,并重复这一过程 log2^K 次。

image.png

把 list 数组当成队列使用,合并 2 条链表后的重新 push,从头部 shift

function ListNode(val){
  this.val = val
  this.next = null
}
var mergeKLists = function(lists) {
  // 边际情况
  if(lists.length===0) return null
  // 只剩一个链表,停止递归
  if(lists.length===1) return lists[0]

  let l1 = lists.shift(),
      l2 = lists.shift()
  let dummyHead = cur = new ListNode(-1)
  while(l1 && l2){
    if(l1.val<l2.val){
      cur.next = l1
      l1 = l1.next
    }else{
      cur.next = l2
      l2 = l2.next
    }
    cur = cur.next
  }
  if(!l1) cur.next = l2
  else  cur.next = l1
  // 处理头部
  const head = dummyHead.next
  dummyHead.next = null
  lists.push(head)
  return mergeKLists(lists)
}

复杂度分析